home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / BNU202.ZIP / FUTIL.ASM < prev    next >
Assembly Source File  |  1989-07-31  |  17KB  |  647 lines

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;
  3. ;;    FOSSIL/Modem Testing Utility
  4. ;;    Copyright (c)  June, 1992
  5. ;;    Unique Computing Pty Limited & David Nugent
  6. ;;    FidoNet Node 3:632/348.0
  7. ;;    Alternet Node 7:833/387.0
  8. ;;
  9. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  10.  
  11. ;
  12. ; This utility is useful for testing various aspects of FOSSIL-aware software,
  13. ; by simulating a modem and enabling the user to set or reset certain status
  14. ; information returned by the FOSSIL to an application.
  15. ;
  16. ; It was created primarily to simulate a remote modem connect for testing
  17. ; purposes using a direct wire but allowing direct control from local keyboard.
  18. ;
  19. ; FUTIL installs as a TSR wedge between the FOSSIL and an application.  It
  20. ; requires that a revision 5 FOSSIL driver be installed prior to it, and it
  21. ; will capture INT 14H (it looks like a FOSSIL to the application) and
  22. ; intercept certain FOSSIL calls in order to carry out its simulation.
  23. ;
  24. ; This utility is particularly useful because it is release WITH SOURCE.
  25. ; It can therefore be modified and re-assembled to carry out any simulation
  26. ; required, but this will take a little knowledge in how FOSSIL operates
  27. ; and some expertise in PC operations in general.
  28. ;
  29. ; Please read the accompanying documentation for license details and caveats.
  30. ;
  31.  
  32. ; V1.00 June 1992        Original release
  33. ; V1.10 July 1992        Small bug fix: purging FOSSIL
  34. ;                receive buffer now clears pending input
  35. ;                status bit (previously this would look
  36. ;                effectively hang a machine with some s/w).
  37.  
  38. ;
  39. ; NOTE: MASM 5.10 or TASM 1.0 is required to assembly this program!
  40. ;       Earlier versions of MASM will NOT work.
  41. ;
  42. ; Provides TASM->MASM compatibility
  43.  
  44. ifdef ??version
  45.     masm51
  46.     quirks
  47. endif
  48.  
  49. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  50. ;;
  51. ;; Definitions/readability section
  52. ;;
  53. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  54.  
  55. CDSIG        equ 0F23DH        ; FUTIL's signature
  56. MAGIC        equ 01954H        ; FOSSIL's magic number
  57. DOS        equ 021H        ; DOS interrupt
  58. TSR        equ 027H        ; .COM TSR call
  59. ; Keyboard shift key codes
  60. CTRL        equ 004H        ; Ctrl key is down
  61. SHIFTS        equ 003H        ; Any shift pressed
  62. LSHIFT        equ 002H        ; Left shift
  63. RSHIFT        equ 001H        ; Right shift
  64. ALT        equ 008h        ; Alt key pressed
  65. NUMLOCK        equ 020H        ; Numlock state
  66. ; BIOS ports, data area definitions
  67. SH_STATE    equ 0417H        ; Shift state byte
  68. KBD_PORT    equ 060H        ; Keyboard data port
  69. KBD_CTRL    equ 061h        ; Keyboard control port
  70. LSC        equ (LSHIFT or CTRL)    ; Shorthand for Ctrl-LShift
  71. KUSED        equ 0FH            ; Bits used in shift mask
  72. ; FOSSIL status bits
  73. PS_CARRIER    equ    0080H        ; Carrier signal from MSREG
  74. PS_RXCHARS    equ    0100H        ; Characters in input buffer
  75.  
  76.  
  77. ;;;;;;;;;;;;;;;;
  78. ;;
  79. ;; Start program
  80. ;;
  81. ;;;;;;;;;;;;;;;;
  82.  
  83. _code segment para public 'code'
  84.     assume CS:_code
  85.     org 100h            ; .COM start
  86.  
  87. ; Jump to install (which is unloaded on TSR
  88.  
  89. start:
  90.     jmp install
  91.  
  92. ;
  93. ; Int 14H entry point
  94. ;
  95.     even
  96. Int_14:
  97.     jmp SHORT parse
  98.  
  99. ;
  100. ; FOSSIL data section
  101. ;
  102.  
  103. oldvec    dd 0                ; Old INT 14H vector
  104.     dw MAGIC            ; Make it look like a FOSSIL
  105.     dw 001bH            ; Revision 5 type
  106.     dw CDSIG
  107. kbdvec    dd 0                ; Old INT 09H vector
  108. ;
  109. port    dw 0                ; Port number
  110. ;
  111. ; Status information
  112. ;
  113. ; WARNING: DO NOT CHANGE THE ORDER AND CONTENTS OF THIS SECTION
  114. ;          WITHOUT CONSIDERING THE 'HOTKEYS' SECTION BELOW.  THESE
  115. ;          VARIABLES CORRESPOND DIRECTLY TO THE HOKEY STRUCTURE!!
  116. ;
  117. even
  118. cstate    dw 0                ; Carrier detect mask (default no extra)
  119. cdmask    dw -1                ; Status mask out bits (default leave alone)
  120. tdata    dw 0                ; Ignore transmit data flag
  121. rdata    dw 0                ; Receive data flag
  122. isdata    dw 0                ; Is data to send flag
  123. strp    dw 0                ; Pointer to current string
  124.  
  125. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  126. ;;
  127. ;;    INT 14H handler
  128. ;;    Only a subset of commands are intecepted
  129. ;;    Tests code in AH, otherwise passes control
  130. ;;    to the installed FOSSIL driver
  131. ;;
  132. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  133.  
  134. parse    PROC NEAR
  135.  
  136.     sti
  137.     cld
  138.     cmp DL,BYTE PTR CS:[port]        ; Select only for current port
  139.     je @F
  140.     jmp DWORD PTR CS:[oldvec]
  141. @@:
  142.     cmp AH,01H            ; Transmit data
  143.     je @istxch
  144.     cmp AH,02H            ; Receive data
  145.     je @isrxch
  146.     cmp AH,03H            ; Port status
  147.     jne @F
  148.     jmp @isstat
  149. @@:
  150.     cmp AH,0AH            ; Receive buffer purge
  151.     je @isrp
  152.     cmp AH,0BH            ; Transmit no wait
  153.     je @istxnw
  154.     cmp AH,0CH            ; Read, no wait
  155.     je @ispeek
  156.     cmp AH,18H            ; Receive block
  157.     jne @F
  158.     jmp @isrxb
  159. @@:
  160.     cmp AH,19H            ; Transmit block
  161.     jne @norm
  162.     jmp @istxb
  163.  
  164.  
  165. ; ---------------------
  166. ; Read, non-destructive
  167. ; ---------------------
  168.  
  169. @ispeek:
  170.     cmp CS:[isdata],0        ; Is there data to be returned?
  171.     je @norm
  172.     push BX
  173.     mov BX,CS:[strp]
  174.     mov AL,CS:[BX]            ; Get next character
  175.     pop BX
  176.     xor AH,AH
  177.     jmp @bye
  178.  
  179. ; ---------------------
  180. ; Transmit no wait call
  181. ; ---------------------
  182.  
  183. @istxnw:
  184.     cmp CS:[tdata],0        ; Eat character
  185.     je @norm
  186.     mov AX,1            ; 1 = successfully sent
  187.     jmp @bye
  188.  
  189. ; -----------------------------------------
  190. ; Purge receive buffers (and pending input)
  191. ; -----------------------------------------
  192.  
  193. @isrp:
  194.     mov CS:[isdata],0
  195.     mov CS:[strp],0
  196.     and CS:[cstate],not PS_RXCHARS    ; Reset "chrs in rx buf" status bit
  197.     jmp SHORT @norm
  198.  
  199. ; ------------------
  200. ; Transmit character
  201. ; ------------------
  202.  
  203. @istxch:
  204.     cmp CS:[tdata],0        ; Eat character
  205.     jne @F
  206.     jmp @isstat
  207. @@:
  208.     mov AL,03H            ; Force a status call
  209.     jmp @isstat
  210.  
  211. @norm:
  212.     jmp DWORD PTR CS:[oldvec]    ; Jump straight to old vector
  213.  
  214. ; -----------------
  215. ; Receive character
  216. ; -----------------
  217.  
  218. @isrxch:
  219.     cmp CS:[isdata],0        ; Is there data to be returned?
  220.     je @rch
  221. @isrxch1:
  222.     push BX
  223.     mov BX,CS:[strp]
  224.     mov AX,CS:[BX]            ; Get next character
  225.     pop BX
  226.     inc CS:[strp]            ; Move pointer to next character
  227.     or AH,AH            ; Test for end of string
  228.     jne @F
  229.     and CS:[cstate],not PS_RXCHARS    ; Reset "chrs in rx buf" status bit
  230.     mov CS:[isdata],0
  231. @@:
  232.     xor AH,AH
  233.     jmp SHORT @bye
  234.  
  235. @rch:
  236.     cmp CS:[rdata],0        ; Give control to FOSSIL?
  237.     je @norm
  238.     sti
  239.     push AX
  240.     mov AH,3            ; Else get status
  241.     int 14H
  242.     test AX,PS_RXCHARS        ; Are there characters in buffer?
  243.     pop AX
  244.     je @isrxch
  245.     cmp CS:[isdata],0        ; Is there data to be returned?
  246.     jne @isrxch1
  247.     jmp SHORT @norm
  248.  
  249. ; -------------------
  250. ; Transmit block data
  251. ; -------------------
  252.  
  253. @istxb:
  254.     cmp CS:[tdata],0        ; Eat character
  255.     je @norm
  256.     mov AX,CX            ; Return number of characters 'sent'
  257.     jmp SHORT @bye
  258.  
  259. ; ------------------
  260. ; Receive block data
  261. ; ------------------
  262.  
  263. @isrxb:
  264.     cmp CS:[isdata],0        ; Is there data to be returned?
  265.     je @norm
  266.     push DI                ; Hmm, better get to work ...
  267.     push CX
  268.     push BX
  269.  
  270.     cld                ; Required for string opcodes
  271.     mov BX,CS:[strp]        ; Get pointer to string
  272.     jcxz @up            ; Opps, zero chrs requested
  273. @@:
  274.     mov AX,CS:[BX]            ; Get next character
  275.     inc BX
  276.     stosb                ; Store it in user buffer
  277.     or AH,AH            ; Test for end of string
  278.     je @F
  279.     loop @B                ; Until user buffer full
  280.     jmp SHORT @up
  281. @@:                    ; No more available at this point
  282.     and CS:[cstate],not PS_RXCHARS    ; Reset "rx chrs avail" status bit
  283.     mov CS:[isdata],0
  284.     xor BX,BX
  285. @up:
  286.     mov CS:[strp],BX        ; Update string pointer
  287.     mov AX,CX            ; Save remaining number of characters
  288.  
  289.     pop BX                ; Restore all registers
  290.     pop CX
  291.     pop DI
  292.     sub AX,CX            ; Calculate/return # of bytes received
  293.     neg AX
  294.     jmp SHORT @bye
  295.  
  296. ; -------------------
  297. ; Status call handler
  298. ; -------------------
  299.  
  300. @isstat:
  301.     pushf                ; Simulate the old INT 14H
  302.     call DWORD PTR CS:[oldvec]
  303.     or AX,CS:[cstate]        ; OR  in set mask
  304.     and AX,CS:[cdmask]        ; AND out reset mask
  305. @bye:
  306.     iret                ; Return to user
  307.  
  308. parse    ENDP
  309.  
  310.  
  311. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  312. ;;
  313. ;; Configuration section
  314. ;;
  315. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  316.  
  317. ;
  318. ; This section contains information which can be modified to suit.
  319. ;
  320.  
  321. ;
  322. ; Modem control strings
  323. ; Various strings returned by a typical modem, available by 'hotkey'
  324. ;
  325.  
  326. ; STATUS
  327. nocarrier    db    'NO CARRIER',13,10,0
  328. ok           db 'OK',13,10,0
  329. error        db 'ERROR',13,10,0
  330. busy         db 'BUSY',13,10,0
  331. ring         db 'RING',13,10,0
  332. rring        db 'RRING',13,10,0
  333. voice        db 'VOICE',13,10,0
  334. ; CONNECTS
  335. connect      db 'CONNECT',13,10,0
  336. connect300   db 'CONNECT 300',13,10,0
  337. connect1200  db 'CONNECT 1200',13,10,0
  338. connect2400  db 'CONNECT 2400',13,10,0
  339. connect24rel db 'CONNECT 2400/REL',13,10,0
  340. connect9600  db 'CONNECT 9600',13,10,0
  341. connectfast  db 'CONNECT FAST',13,10,0
  342.  
  343.  
  344. ;
  345. ; This next section is a series of structures which allows a 'hotkey'
  346. ; combination to be tied to a given action.  The structures contain the
  347. ; contents of the INT 14H variables used in the above intercept routines
  348. ; and pressing the hotkey combination simply copies in values for these
  349. ; variables setting of a reaction by the next intercepted INT 14H call.
  350. ;
  351.  
  352. notkey STRUC
  353.  scanc  db ?        ; Keyboard scan code (returned by KB ROM)
  354.  kshft  db ?        ; Keyboard shift state (BIOS)
  355.  cmask    dw ?        ; Status OR mask (force these bits on)
  356.  cbits  dw ?        ; Status AND mask (force these bits off)
  357.  itx    dw ?        ; Ignore transmited data flag (don't give to FOSSIL)
  358.  irx    dw ?        ; Don't call FOSSIL to receive data flag
  359.  srx    dw ?        ; Is there data to 'receive' flag
  360.  dofs    dw ?        ; Offset of string to 'receive'
  361. notkey ENDS
  362.  
  363. SZ_ka    equ <size notkey>        ; Size of one hotkey structure
  364.  
  365. KEYS equ 20                ; Defines how many structures to scan
  366.  
  367. ;
  368. ; Hot keys table
  369. ;
  370. even
  371. KeyCodes label word
  372. notkey <29H, LSC, 0000H, not 0000H, 00H, 00H, 00H, 0           >  ; cs` Turns all processing off
  373. notkey <0bH, LSC, 0000H, not 0080H, 00H, 00H, 00H, 0           >  ; cs0 Force no carrier
  374. notkey <18H, LSC, 0100H, not 0080H, 00H, 01H, 01H, ok          >  ; csO 'OK'
  375. notkey <12H, LSC, 0100H, not 0080H, 00H, 01H, 01H, error       >  ; csE 'ERROR'
  376. notkey <31H, LSC, 0100H, not 0080H, 00H, 01H, 01H, nocarrier   >  ; csN 'NO CARRIER'
  377. notkey <30H, LSC, 0100H, not 0080H, 00H, 01H, 01H, busy        >  ; csB 'BUSY'
  378. notkey <21H, LSC, 0180H, not 0000H, 00H, 01H, 01H, connectfast >  ; csF 'CONNECT FAST'
  379. notkey <0aH, LSC, 0180H, not 0000H, 00H, 01H, 01H, connect9600 >  ; cs9 'CONNECT 9600'
  380. notkey <04H, LSC, 0180H, not 0000H, 00H, 01H, 01H, connect24rel>  ; cs3 'CONNECT 2400/REL'
  381. notkey <03H, LSC, 0180H, not 0000H, 00H, 01H, 01H, connect2400 >  ; cs2 'CONNECT 2400'
  382. notkey <02H, LSC, 0180H, not 0000H, 00H, 01H, 01H, connect1200 >  ; cs1 'CONNECT 1200'
  383. notkey <13H, LSC, 0100H, not 0080H, 00H, 01H, 01H, ring        >  ; csR 'RING'
  384. notkey <2fH, LSC, 0100H, not 0080H, 00H, 01H, 01H, voice       >  ; csV 'VOICE'
  385. notkey <17H, LSC, 0100H, not 0080H, 00H, 01H, 01H, rring       >  ; csI 'RRING'
  386. notkey <00H, 00H, 0000H, not 0000H, 00H, 00H, 00H, 0           >
  387. notkey <00H, 00H, 0000H, not 0000H, 00H, 00H, 00H, 0           >
  388. notkey <00H, 00H, 0000H, not 0000H, 00H, 00H, 00H, 0           >
  389. notkey <00H, 00H, 0000H, not 0000H, 00H, 00H, 00H, 0           >
  390. notkey <00H, 00H, 0000H, not 0000H, 00H, 00H, 00H, 0           >
  391. notkey <00H, 00H, 0000H, not 0000H, 00H, 00H, 00H, 0           >
  392.  
  393.  
  394. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  395. ;;
  396. ;;    Keyboard (hardware) interrupt handler
  397. ;;
  398. ;;    This routine is triggered on make or break (press or release)
  399. ;;    of ANY key on the keyboard.  The KB port is then inspected to
  400. ;;    see which key was pressed, and the current shift status read.
  401. ;;    The above hotkeys table is then scanned for a match; if found,
  402. ;;    the rest of the structure is copied into the variable space,
  403. ;;    otherwise the call passes to the previous INT 9H handler.
  404. ;;
  405. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  406.  
  407.  
  408. Int_9 PROC FAR
  409.  
  410.     assume DS:nothing,ES:nothing    ; Could (and will) be anywhere
  411.  
  412.     push AX                ; Must preserve EVERY register here
  413.     push CX
  414.     push DI
  415.     push ES
  416.     xor AX,AX
  417.     mov ES,AX
  418.  
  419.     in AL,KBD_PORT            ; Scan code of key pressed
  420.     mov AH,ES:[SH_STATE]        ; Current shift state bits
  421.     and AH,KUSED            ; Mask out unused bits
  422.     mov DI,offset KeyCodes        ; Scan key codes table
  423.     mov CX,KEYS
  424. @@:
  425.     cmp AX,CS:[DI]
  426.     je @F
  427.     add DI,SZ_ka
  428.     loop @B
  429.                     ; Key was not found
  430.     pop ES                ; Restore saved registers
  431.     pop DI
  432.     pop CX
  433.     pop AX
  434.     jmp CS:[kbdvec]            ; Pass though to original vector
  435.  
  436. ;
  437. ; Key combo found; take action
  438. ;
  439.  
  440. @@:
  441.     in AL,KBD_CTRL            ; Save value of kbd control lines
  442.     mov AH,AL
  443.     or AL,80H            ; Set kbd enable bit
  444.     out KBD_CTRL,AL
  445.     mov AL,AH
  446.     out KBD_CTRL,AL
  447.     mov AL,20H            ; Signal end of HW interrupt to 8259A
  448.     out 20H,AL
  449.     push BX
  450.     xor BX,BX
  451.     mov CX,SZ_ka/2
  452.     jmp SHORT @F
  453. @Clp:
  454.     mov AX,CS:[DI+BX]        ; Copy variables to intercept data area
  455.     mov CS:[BX+offset cstate-2],AX
  456. @@:
  457.     inc BX
  458.     inc BX
  459.     loop @Clp
  460.  
  461.     pop BX                ; Restore registers
  462.     pop ES
  463.     pop DI
  464.     pop CX
  465.     pop AX
  466.     iret
  467.  
  468. Int_9 ENDP
  469.  
  470.  
  471. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  472. ;;
  473. ;;    End resident section
  474. ;;
  475. ;;    The rest of this code is discarded on installation as a TSR, and
  476. ;;    does not consume additional memory
  477. ;;
  478. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  479.  
  480. ; Installation messages
  481.  
  482. msg_nofos    db 7,'No FOSSIL driver installed',13,10,'$'
  483. msg_instald  db 7,'FUTIL is already installed',13,10,'$'
  484. msg_instnot  db 7,'FUTIL is not installed',13,10,'$'
  485. msg_instok   db 'FUTIL is now active',13,10,'$'
  486. msg_inval    db 7,'Invalid command line option',13,10,'$'
  487. msg_unloaded db 'FUTIL successfully unloaded',13,10,'$'
  488. msg_start    db 'FUTIL v1.10  FOSSIL Communications Companion Utility',13,10
  489.              db 'Copyright (C) 1992  David Nugent & Unique Computing Pty Ltd',13,10
  490.              db '$'
  491.  
  492. ; ----------------------
  493. ; Installation procedure
  494. ; ----------------------
  495.  
  496. install PROC NEAR
  497.     assume ds:_code                ; DS = CS by default
  498.     mov DX,offset msg_start            ; Output our logo
  499.     mov AH,9
  500.     int DOS
  501.     cld                    ; Required for string opcodes
  502.     mov SI,81H                ; Start of command line
  503. @Top:
  504.     lodsb
  505.     cmp AL,13                ; Test for end of cmdline
  506.     je @Load
  507.     cmp AL,0
  508.     je @Load
  509.     cmp AL,32                ; Skip spaces,
  510.     je @Top
  511.     cmp AL,9                ; and tabs
  512.     je @Top
  513.     cmp AL,'/'                ; Looking for a valid switch
  514.     je @F                    ; character (- or / will do)
  515.     cmp AL,'-'
  516.     je @F
  517. @nogood:
  518.     mov AL,3                ; Something else is invalid
  519.     mov DX,offset msg_inval
  520.     jmp ExitMsg
  521. ;
  522. ; Read switch value
  523. ;
  524. @@:
  525.     lodsb
  526.     cmp AL,'a'                ; Convert to uppercase
  527.     jb @F
  528.     cmp AL,'z'
  529.     ja @F
  530.     sub AL,'a'-'A'
  531. @@:
  532.     cmp AL,'U'                ; /U = Uninstall
  533.     je @Unload
  534.     cmp AL,'P'                ; /P = Port number
  535.     jne @nogood
  536.     lodsb
  537.     cmp AL,'0'                ; Convert # to binary
  538.     jb @nogood
  539.     cmp AL,'9'
  540.     ja @nogood
  541.     sub AL,'0'
  542.     xor AH,AH
  543.     mov port,AX                ; Save in our local variable
  544.     jmp SHORT @Top
  545.  
  546. ;
  547. ; Unload from memory
  548. ;
  549.  
  550. @Unload:
  551.     call ChkLoad                ; See if FUTIL is loaded
  552.     cmp ES:[BX+10],CDSIG            ; Is this program installed?
  553.     mov DX,offset msg_instnot
  554.     mov AL,2
  555.     jne ExitMsg
  556.     push DS                    ; Preserve DS for later
  557.     push ES
  558.     push ES
  559.     pop DS
  560.     mov DX,word ptr [kbdvec]
  561.     mov DS,word ptr [kbdvec+2]
  562.     mov AX,2509H                ; Release keyboard
  563.     int DOS
  564.     pop DS
  565.     mov DX,word ptr [oldvec]
  566.     mov DS,word ptr [oldvec+2]
  567.     mov AX,2514H                ; Release INT 14H
  568.     int DOS
  569.     pop DS
  570.     mov AH,49H                ; Deallocate memory (at ES)
  571.     int DOS
  572.     mov DX,offset msg_unloaded
  573.     xor AL,AL
  574.     jmp SHORT ExitMsg
  575.  
  576. ;
  577. ; Load into memory
  578. ;
  579.  
  580. @Load:
  581.     call ChkLoad                ; Check to see if we're loaded
  582.     cmp ES:[BX+10],CDSIG            ; Is this program installed?
  583.     mov DX,offset msg_instald
  584.     mov AL,2
  585.     je ExitMsg
  586.     mov DX,offset Int_14            ; Install vector for INT 14H
  587.     mov AX,2514H
  588.     int DOS
  589.     mov AX,3509H                ; Get keyboard vector
  590.     int DOS
  591.     mov word ptr [kbdvec],BX
  592.     mov word ptr [kbdvec+2],ES
  593.     mov DX,offset Int_9
  594.     mov AX,2509H                ; Intercept keyboard
  595.     int DOS
  596.     mov AX,CS
  597.     mov ES,AX
  598.     mov ES,ES:[02cH]            ; Free our environment
  599.     mov AH,049H
  600.     int DOS
  601.     mov DX,offset msg_instok
  602.     mov AH,09H                ; Print message
  603.     int DOS
  604.     mov DX,offset msg_nofos            ; Stay resident
  605.     int TSR
  606.  
  607. install ENDP
  608.  
  609. ;
  610. ; Exit (abort) with a message
  611. ;
  612.  
  613. ExitMsg    PROC NEAR
  614.  
  615.     push AX                    ; Save exit code
  616.     mov AH,09H                ; Print message
  617.     int DOS
  618.     pop AX
  619.     mov AH,4cH                ; And exit
  620.     int DOS
  621.  
  622. ExitMsg ENDP
  623.  
  624. ;
  625. ; Check to see if already loaded
  626. ;
  627.  
  628. ChkLoad PROC NEAR
  629.     mov AX,3514H                ; Get int 14H vector
  630.     int DOS
  631.     mov word ptr [oldvec],BX        ; And save it
  632.     mov word ptr [oldvec+2],ES
  633.     cmp ES:[BX+6],MAGIC            ; Is a FOSSIL there?
  634.     mov DX,offset msg_nofos
  635.     mov AL,1
  636.     je @F
  637.     pop BX
  638.     mov BX,offset ExitMsg
  639.     push BX
  640. @@:
  641.     ret
  642. ChkLoad ENDP
  643.  
  644. _code ends
  645.  
  646. end start
  647.